///////////////////////////////////////////////////////////////////////////////
//
// lighthouse3D - 3D Software Library
//
// File: CFileHandler.cpp
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2013 Marcus Reinhardt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
//
// You can find a copy of the GNU General Public License (gpl.txt) in the
// directory of the library.
//
///////////////////////////////////////////////////////////////////////////////
#include "CFileHandler.h"

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::CFileHandler( ... )
///////////////////////////////////////////////////////////////////////////////
CFileHandler::CFileHandler()
{
  setErrorLevel(_noFileError_);
  color3DSFailure = 255*256*256;
  colorOBJFailure = 255*256*256;
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::~CFileHandler( ... )
///////////////////////////////////////////////////////////////////////////////
CFileHandler::~CFileHandler()
{
  release();
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::release( ... )
///////////////////////////////////////////////////////////////////////////////
void CFileHandler::release()
{
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadImageToPicture( ... )
///////////////////////////////////////////////////////////////////////////////
// loads an Image file into a TPictureData object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadImageToPicture(const char *fname, TPictureData *picHandler)
{
     char ext[128];
     char name[128];

	 strcpy(name, fname);

	 getExtensionFromFilename(name, ext);
     
     if ( (strcmp(ext, "tga") == 0) || (strcmp(ext, "TGA") == 0) )
     {

         if ( loadTGAToPicture(fname, picHandler) == false) 
             return false;
         else
             return true;
         
     }
     
     if ( (strcmp(ext, "bmp") == 0) || (strcmp(ext, "BMP") == 0) )
     {

         if ( loadBMPToPicture(fname, picHandler) == false) 
			 return false;
		 else
			 return true;

	 }

	 return false;
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadBMPToPicture( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a BMP file into a TPictureData object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadBMPToPicture(const char *fname, TPictureData *picHandler)
{
  int x,y,qPic,qPic2;

  setErrorLevel(_noFileError_);

  if ( fileHandlerBMP.loadBMPFile(fname) == false )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }

  // Converter TPictureData to TMeshTexture
  if ( fileHandlerBMP.getPicDataHandle()->sizeX > _maxPicSizeX_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }
  if ( fileHandlerBMP.getPicDataHandle()->sizeY > _maxPicSizeY_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }

  picHandler->sizeX = fileHandlerBMP.getPicDataHandle()->sizeX;
  picHandler->sizeY = fileHandlerBMP.getPicDataHandle()->sizeY;

  for(x=0; x<(int)picHandler->sizeX; x++) {

    for(y=0; y<(int)picHandler->sizeY; y++) {

      qPic = (picHandler->sizeY-(y+1))*picHandler->sizeX+x;
      qPic2 = y*picHandler->sizeX+x;
      picHandler->rgb[qPic] = fileHandlerBMP.getPicDataHandle()->rgb[qPic2];

    }

  }

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadTGAToPicture( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a TGA file into a TPictureData object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadTGAToPicture(const char *fname, TPictureData *picHandler)
{

  int x,y,qPic,qPic2;

  setErrorLevel(_noFileError_);

  if ( fileHandlerTGA.loadTGAFile(fname) == false )
  {
      setErrorLevel(_errorOnLoadingTGAFile_);
      
      return false;
  }

  // Converter TPictureData to TMeshTexture
  if ( fileHandlerTGA.getPicDataHandle()->sizeX > _maxPicSizeX_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }
  if ( fileHandlerTGA.getPicDataHandle()->sizeY > _maxPicSizeY_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }

  picHandler->sizeX = fileHandlerTGA.getPicDataHandle()->sizeX;
  picHandler->sizeY = fileHandlerTGA.getPicDataHandle()->sizeY;

  for(x=0; x<(int)picHandler->sizeX; x++) {

    for(y=0; y<(int)picHandler->sizeY; y++) {

      qPic = (picHandler->sizeY-(y+1))*picHandler->sizeX+x;
      qPic2 = y*picHandler->sizeX+x;
      picHandler->rgb[qPic] = fileHandlerTGA.getPicDataHandle()->rgb[qPic2];

    }

  }

  return true;
  
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadImageToTexture( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a Image file into a TMeshTexture object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadImageToTexture(const char *fname, TMeshTexture *texHandler)
{
     char ext[128];
     char name[128];
     
     strcpy(name, fname);
     
     getExtensionFromFilename(name, ext);
     
     if ( (strcmp(ext, "tga") == 0) || (strcmp(ext, "TGA") == 0) )
     {

         if ( loadTGAToTexture(fname, texHandler) == false) 
             return false;
         else
             return true;
         
     }
     
     if ( (strcmp(ext, "bmp") == 0) || (strcmp(ext, "BMP") == 0) )
     {

         if ( loadBMPToTexture(fname, texHandler) == false) 
             return false;
         else
             return true;

     }
  	
	 return false;
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadBMPToTexture( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a BMP file into a TMeshTexture object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadBMPToTexture(const char *fname, TMeshTexture *texHandler)
{
  int x,y,qTex,qPic;

  setErrorLevel(_noFileError_);

  if ( fileHandlerBMP.loadBMPFile(fname) == false )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }

  texHandler->release();

  // Converter TPictureData to TMeshTexture
  if ( fileHandlerBMP.getPicDataHandle()->sizeX > _maxTexSizeX_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }
  if ( fileHandlerBMP.getPicDataHandle()->sizeY > _maxTexSizeY_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }

  texHandler->m_width = fileHandlerBMP.getPicDataHandle()->sizeX;
  texHandler->m_height = fileHandlerBMP.getPicDataHandle()->sizeY;

  for(y=0; y<(int)texHandler->m_height; y++) {

    for(x=0; x<(int)texHandler->m_width; x++) {

      qTex = y*texHandler->m_width+x;
      qPic = (texHandler->m_height-(y+1))*texHandler->m_width+x;
      texHandler->m_image[qTex] = fileHandlerBMP.getPicDataHandle()->rgb[qPic];

    }

  }

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadTGAToTexture( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a TGA file into a TMeshTexture object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadTGAToTexture(const char *fname, TMeshTexture *texHandler)
{
  int x,y,qTex,qPic;

  setErrorLevel(_noFileError_);

  if ( fileHandlerTGA.loadTGAFile(fname) == false )
  {
      setErrorLevel(_errorOnLoadingTGAFile_);
      
      return false;
  }

  texHandler->release();

  // Converter TPictureData to TMeshTexture
  if ( fileHandlerTGA.getPicDataHandle()->sizeX > _maxTexSizeX_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }
  if ( fileHandlerTGA.getPicDataHandle()->sizeY > _maxTexSizeY_ )
  {
      setErrorLevel(_errorOnLoadingBMPFile_);

      return false;
  }

  texHandler->m_width = fileHandlerTGA.getPicDataHandle()->sizeX;
  texHandler->m_height = fileHandlerTGA.getPicDataHandle()->sizeY;

  for(y=0; y<(int)texHandler->m_height; y++) {

    for(x=0; x<(int)texHandler->m_width; x++) {

      qTex = y*texHandler->m_width+x;
      qPic = (texHandler->m_height-(y+1))*texHandler->m_width+x;
      texHandler->m_image[qTex] = fileHandlerTGA.getPicDataHandle()->rgb[qPic];

    }

  }

  return true;
  
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::load3DSToMeshStorage ( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a 3DS file into a CMeshStorage object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::load3DSToMeshStorage(const char *fname, CMeshStorage *storageHandler)
{
  char ext[128];
  char path[1024];
  char newFName[1024];
  
  int i, j;
  int meshCount = storageHandler->getMeshCount();
  
  TMeshTriangle *t;

  setErrorLevel(_errorOnLoadingBMPFile_);

  if ( fileHandler3DS.load3DSFile(fname, storageHandler) == false )
  {
      setErrorLevel(_errorOnLoading3DSFile_);
      
      return false;
  }
      
  // postprocessing the data structure
      
  if (meshCount != storageHandler->getMeshCount())
  {
 
     for (i = meshCount; i < storageHandler->getMeshCount(); i++) {

         for (j = 0; j < storageHandler->getMesh(i)->getFaceCount(); j++) {
      
              t = storageHandler->getMesh(i)->getFace(j);
           
              t->ut[0] = storageHandler->getMesh(i)->getVert(t->v[0])->u;
              t->vt[0] = 1-storageHandler->getMesh(i)->getVert(t->v[0])->v;
              t->ut[1] = storageHandler->getMesh(i)->getVert(t->v[1])->u;
              t->vt[1] = 1-storageHandler->getMesh(i)->getVert(t->v[1])->v;
              t->ut[2] = storageHandler->getMesh(i)->getVert(t->v[2])->u;
              t->vt[2] = 1-storageHandler->getMesh(i)->getVert(t->v[2])->v;
                    
         }
         
     }
  
  }
  
  // postprocessing the textures      
  if (meshCount != storageHandler->getMeshCount())
  {
 
     for (i = meshCount; i < storageHandler->getMeshCount(); i++) {

         for (j = 0; j < storageHandler->getMesh(i)->getFaceCount(); j++) {
      
              storageHandler->getMesh(i)->getFace(j)->texture += storageHandler->getTexCount();
           
         }
         
     }
  
  }
  
  getPathFromFilename((char*)fname, path);

  // loading the textures  
  for (i = 0; i<fileHandler3DS.getTexListHandle()->n; i++)
  {
     tex.release();
	
     strcpy(newFName, path);
     strcat(newFName, fileHandler3DS.getTexListHandle()->textures[i].fileName);
     
     getExtensionFromFilename(fileHandler3DS.getTexListHandle()->textures[i].fileName, ext);

     if ( (strcmp(ext, "tga") == 0) || (strcmp(ext, "TGA") == 0) )
     {
         if ( loadTGAToTexture(newFName, &tex) == false) 
         {     
             tex.m_height = 1;
             tex.m_width = 1;
             tex.m_image[0] = color3DSFailure;
             tex.m_image[1] = color3DSFailure;
             tex.m_image[2] = color3DSFailure;
             tex.m_image[3] = color3DSFailure;
         }
         
         strcpy(tex.m_name, fileHandler3DS.getTexListHandle()->textures[i].description);
     
         storageHandler->addTex(tex);                  
     }
     
     if ( (strcmp(ext, "bmp") == 0) || (strcmp(ext, "BMP") == 0) )
     {
         if ( loadBMPToTexture(newFName, &tex) == false) 
         {     
             tex.m_height = 1;
             tex.m_width = 1;
             tex.m_image[0] = color3DSFailure;
             tex.m_image[1] = color3DSFailure;
             tex.m_image[2] = color3DSFailure;
             tex.m_image[3] = color3DSFailure;
         }
         
         strcpy(tex.m_name, fileHandler3DS.getTexListHandle()->textures[i].description);
     
         storageHandler->addTex(tex);
     }
  
  }
  
  return true;

}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::loadOBJToMeshStorage ( ... )
///////////////////////////////////////////////////////////////////////////////
// loads a OBJ file into a CMeshStorage object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::loadOBJToMeshStorage(const char *fname, CMeshStorage *storageHandler)
{
  int i, j;
  int meshCount = storageHandler->getMeshCount();
  
  TMeshTriangle *t;

  if ( fileHandlerOBJ.loadOBJFile(fname, storageHandler) == false )
  {
      setErrorLevel(_errorOnLoadingOBJFile_);
      
      return false;
  }

  // postprocessing the data structure      
  if (meshCount != storageHandler->getMeshCount())
  {
 
     for (i = meshCount; i < storageHandler->getMeshCount(); i++) {

         for (j = 0; j < storageHandler->getMesh(i)->getFaceCount(); j++) {
      
              t = storageHandler->getMesh(i)->getFace(j);
           
              /*t->ut[0] = storageHandler->getMesh(i)->getVert(t->v[0])->u;
              t->vt[0] = 1-storageHandler->getMesh(i)->getVert(t->v[0])->v;
              t->ut[1] = storageHandler->getMesh(i)->getVert(t->v[1])->u;
              t->vt[1] = 1-storageHandler->getMesh(i)->getVert(t->v[1])->v;
              t->ut[2] = storageHandler->getMesh(i)->getVert(t->v[2])->u;
              t->vt[2] = 1-storageHandler->getMesh(i)->getVert(t->v[2])->v;*/
                    
              t->ut[0] = 0;
              t->vt[0] = 0;
              t->ut[1] = 0;
              t->vt[1] = 0;
              t->ut[2] = 0;
              t->vt[2] = 0;
         }
         
     }
  
  }
      
  // postprocessing the textures      
  if (meshCount != storageHandler->getMeshCount())
  {
 
     for (i = meshCount; i < storageHandler->getMeshCount(); i++) {

         for (j = 0; j < storageHandler->getMesh(i)->getFaceCount(); j++) {
      
              storageHandler->getMesh(i)->getFace(j)->texture = 0;
           
         }
         
     }
  
  }
  
  tex.m_height = 1;
  tex.m_width = 1;
  tex.m_image[0] = colorOBJFailure;
  tex.m_image[1] = colorOBJFailure;
  tex.m_image[2] = colorOBJFailure;
  tex.m_image[3] = colorOBJFailure;
         
  strcpy(tex.m_name, "Faked Color Texture");
     
  storageHandler->addTex(tex);

  return true;

}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::saveImageFromPicture( ... )
///////////////////////////////////////////////////////////////////////////////
// save an Image file from a TPictureData object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::saveImageFromPicture(const char *fname, TPictureData *picHandler)
{
     char ext[128];
     char name[128];
     
     strcpy(name, fname);
     
     getExtensionFromFilename(name, ext);
     
     if ( (strcmp(ext, "tga") == 0) || (strcmp(ext, "TGA") == 0) )
     {

         if ( saveTGAFromPicture(fname, picHandler) == false) 
             return false;
         else
             return true;
         
     }
     
     if ( (strcmp(ext, "bmp") == 0) || (strcmp(ext, "BMP") == 0) )
     {

         if ( saveBMPFromPicture(fname, picHandler) == false) 
             return false;
         else
             return true;

     }
	
	 return false;
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::saveBMPFromPicture( ... )
///////////////////////////////////////////////////////////////////////////////
// save a BMP file from a TPictureData object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::saveBMPFromPicture(const char *fname, TPictureData *picHandler)
{
  int x,y;
  unsigned int qPic, qPic2;

  setErrorLevel(_noFileError_);

  picTemp.sizeX = picHandler->sizeX;
  picTemp.sizeY = picHandler->sizeY;

  for(y=0; y<(int)picTemp.sizeY; y++) {

    for(x=0; x<(int)picTemp.sizeX; x++) {

      qPic = y*picTemp.sizeX+x;
      qPic2 = (picTemp.sizeY-(y+1))*picTemp.sizeX+x;
      picTemp.rgb[qPic] = picHandler->rgb[qPic2];

    }

  }

  if ( fileHandlerBMP.saveBMPFile(fname, &picTemp) == false )
  {
      setErrorLevel(_errorOnSavingBMPFile_);
      
      return false;
  }

  return true;  
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::saveTGAFromPicture( ... )
///////////////////////////////////////////////////////////////////////////////
// save a TGA file from a TPictureData object
///////////////////////////////////////////////////////////////////////////////
bool CFileHandler::saveTGAFromPicture(const char *fname, TPictureData *picHandler)
{
  int x,y;
  unsigned int qPic, qPic2;

  setErrorLevel(_noFileError_);

  picTemp.sizeX = picHandler->sizeX;
  picTemp.sizeY = picHandler->sizeY;

  for(y=0; y<(int)picTemp.sizeY; y++) {

    for(x=0; x<(int)picTemp.sizeX; x++) {

      qPic = y*picTemp.sizeX+x;
      qPic2 = (picTemp.sizeY-(y+1))*picTemp.sizeX+x;
      picTemp.rgb[qPic] = picHandler->rgb[qPic2];

    }

  }

  if ( fileHandlerTGA.saveTGAFile(fname, &picTemp) == false )
  {
      setErrorLevel(_errorOnSavingTGAFile_);
      
      return false;
  }

  return true;  
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::getExtensionFromFilename ( ... )
///////////////////////////////////////////////////////////////////////////////
// Extracts the extension from a given filename
///////////////////////////////////////////////////////////////////////////////
void CFileHandler::getExtensionFromFilename(char *szFileName, char *szExtension)
{
  int len = strlen(szFileName);
  int begin;

  for (begin=len; begin>=0; begin--)
  {
  
     if (szFileName[begin] == '.')
	 {
		begin++;
		break;
	 } 
	 
  }

  if (begin <= 0)
  {
     szExtension[0] = '\0';
  }
  else
  {
     strcpy(szExtension, &szFileName[begin]);
  }
}

///////////////////////////////////////////////////////////////////////////////
// CFileHandler::getPathFromFilename ( ... )
///////////////////////////////////////////////////////////////////////////////
// Extracts the path from a given filename
///////////////////////////////////////////////////////////////////////////////
void CFileHandler::getPathFromFilename(char *szFileName, char *szPath)
{
  int len = strlen(szFileName);
  int begin;

  for (begin=len; begin>=0; begin--)
  {
	 if (szFileName[begin] == 92)
	 {
		begin++;
		break;
	 }
	 if (szFileName[begin] == 47)
	 {
		begin++;
		break;
	 }	 
  }

  if (begin <= 0)
  {
     szPath[0] = '\0';
  }
  else
  {
	 strcpy(szPath, szFileName);
     szPath[begin] = '\0';
  }
}

